/*
 *   Copyright (C) 2009  Jens Kieselbach
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You may obtain a copy of the License at http://www.gnu.org/licenses/gpl.html
 */
package de.kieselbach.grootional.dialog


import de.kieselbach.grootional.value.*
import de.kieselbach.swing.*
import de.kieselbach.swing.activation.*
import de.kieselbach.swing.table.*
import de.kieselbach.swing.validation.*

import com.jgoodies.forms.builder.*
import com.jgoodies.forms.layout.*
import com.jgoodies.looks.*
import com.jgoodies.looks.plastic.*
import javax.swing.*
import java.sql.*
import java.util.logging.*

import java.awt.BorderLayout
import java.awt.Dimension

class ConnectionDialog {

    def dialog
    def wasOk = false

    def mainFrame
    def uiResources
    def resourceBundle

    def id
    def descriptionField
    def driverField
    def urlField
    def userField
    def passwordField
    def catalogField
    def schemaField

    def table
    def model
    def propertyKeys = [] as Set

    ConnectionDialog(def mainframe) {

        mainFrame = mainframe
        uiResources = mainframe.uiResources
        resourceBundle = uiResources.resourceBundles['gui']

        def validator = new Validator()

        descriptionField = validator.validate(new JTextField(), Validator.EMPTY_TEXT_CHECKER)
        driverField = validator.validate(new JTextField(), Validator.EMPTY_TEXT_CHECKER)
        urlField = validator.validate(new JTextField(), Validator.EMPTY_TEXT_CHECKER)
        userField = new JTextField()
        passwordField = new JTextField()
        catalogField = new JTextField()
        schemaField = new JTextField()

        // ------------------------------------------------------------------------------

        def catalog = new FlatButton(uiResources.images['find16'] as Icon)

        catalog.toolTipText = resourceBundle.getString('connection.showcatalogs')
        catalog.preferredSize = [schemaField.preferredSize.@height, schemaField.preferredSize.@height] as Dimension

        validator.enable(catalog)

        catalog.actionPerformed = {
            showCatalogsAndSchemas()
        }

        FormLayout layout = new FormLayout("right:pref, 3dlu, fill:110dlu:grow, 5dlu, right:pref, 3dlu, fill:110dlu:grow, 3dlu, pref", "p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p")

        PanelBuilder builder = new PanelBuilder(layout)
        builder.border = BorderFactory.createEmptyBorder(5, 5, 5, 5)
        CellConstraints cc = new CellConstraints()

        builder.addLabel(resourceBundle.getString('connection.description') as String, cc.xy(1, 1))
        builder.add(descriptionField, cc.xyw(3, 1, 7))

        builder.addLabel(resourceBundle.getString('connection.driver') as String, cc.xy(1, 3))
        builder.add(driverField, cc.xyw(3, 3, 7))

        builder.addLabel(resourceBundle.getString('connection.url') as String, cc.xy(1, 5))
        builder.add(urlField, cc.xyw(3, 5, 7))

        builder.addLabel(resourceBundle.getString('connection.user') as String, cc.xy(1, 7))
        builder.add(userField, cc.xyw(3, 7, 7))

        builder.addLabel(resourceBundle.getString('connection.password') as String, cc.xy(1, 9))
        builder.add(passwordField, cc.xyw(3, 9, 7))

        builder.addLabel(resourceBundle.getString('connection.catalog') as String, cc.xy(1, 11))
        builder.add(catalogField, cc.xy(3, 11))
        builder.addLabel(resourceBundle.getString('connection.schema') as String, cc.xy(5, 11))
        builder.add(schemaField, cc.xy(7, 11))
        builder.add(catalog, cc.xy(9, 11))

        // ------------------------------------------------------------------------------

        table = new JTable()
        model = new CommonTableModel([resourceBundle.getString('connection.key'), resourceBundle.getString('connection.value')] as ArrayList)
        model.valueClass = {col ->
            String.class
        }

        model.valueSetter = {rowval, row, col, val ->

            val = val.trim()

            if(col == 0) {
                if(val.length() <= 0) {
                    SwingUtilities.invokeLater {
                        new PaneBuilder().information(resourceBundle.getString('connection.changeproperty'), message: resourceBundle.getString('connection.nokey'), owner: dialog)
                    }
                }
                else if(val != rowval[col] && propertyKeys.contains(val)) {
                    SwingUtilities.invokeLater {
                        new PaneBuilder().information(resourceBundle.getString('connection.changeproperty'), message: resourceBundle.getString('connection.duplicateproperty'), owner: dialog)
                    }                    
                }
                else {
                    propertyKeys.remove(rowval[col])
                    rowval[col] = val
                    propertyKeys << val
                }
            }
            else {
                rowval[col] = val
            }
        }

        table.model = model

        def sb = new ExtendedSwingBuilder()
        def panel = sb.panel(border: BorderFactory.createEmptyBorder(5, 5, 5, 5)) {
            sb.borderLayout()
            scrollPane(preferredSize: [50, 50] as Dimension, constraints: BorderLayout.CENTER) {
                widget(table)
            }
            box(constraints: BorderLayout.SOUTH, border: BorderFactory.createEmptyBorder(3, 0, 0, 0)) {
                flatButton(resourceBundle.getString('connection.add'), icon: uiResources.images['add16'], actionPerformed: {
                    int num = 1
                    def str = resourceBundle.getString('connection.newproperty')
                    def key = str + num
                    while(propertyKeys.contains(key)) {
                        num++
                        key = str + num
                    }

                    propertyKeys << key
                    model.addRow([key, ''])
                })
                flatButton(resourceBundle.getString('connection.delete'), icon: uiResources.images['delete16'], activator: new TableSelectionActivator(table, 1), actionPerformed: {
                    if(table.selectedRowCount > 0) {
                        def sel = table.selectedRows
                        if(sel != null) {
                            def l = model.getRows(sel);
                            l.each() {val ->
                                propertyKeys.remove(val[0])
                            }
                            model.removeRows(table.selectedRows)
                        }
                    }
                })
            }
        }

        // ------------------------------------------------------------------------------

        def tab = new JTabbedPane()
        tab.add(resourceBundle.getString('connection.connection') as String, builder.getPanel())
        tab.add(resourceBundle.getString('connection.properties') as String, panel)

        def panebuilder = new PaneBuilder()
        dialog = panebuilder.dialog(resourceBundle.getString('connection.title.new'), owner: mainFrame.frame, modal: true, resizable: false, pack: true, center: true) {
            pane() {
                widget(tab)
                bar(type: PaneBuilder.DEFAULT, glue: false)  {
                    ok(default: true, validator: validator, actionPerformed: {
                        wasOk = true
                        dialog.visible = false
                    })
                    filler()
                    cancel(actionPerformed: {
                        wasOk = false
                        dialog.visible = false
                    })
                    glue()
                    button(resourceBundle.getString('connection.test'), icon: uiResources.images['connect16'], validator: validator, actionPerformed: {
                        test(null)
                    })
                }
            }
        }
    }

    void show() {
        dialog.setVisible(true)
        dialog.dispose()
    }

    void selectCatalogsAndSchemas(def schemas) {

        def list = new JList(schemas.toArray())
        list.selectionMode = ListSelectionModel.SINGLE_SELECTION
        def scroll = new JScrollPane(list)
        scroll.preferredSize = [400, 300] as Dimension

        def dlg = null
        def okselected = false

        list.mouseClicked = {e ->
            if(e.clickCount == 2) {
                okselected = true
                dlg.visible = false
            }
        }

        def panebuilder = new PaneBuilder()
        dlg = panebuilder.dialog(resourceBundle.getString('connection.catalogs'), owner: dialog, modal: true, resizable: false, pack: true, center: true) {
            pane() {
                widget(scroll)
                bar(type: PaneBuilder.DEFAULT)  {
                    ok(default: true, actionPerformed: {
                        okselected = true
                        dlg.visible = false
                    })
                    filler()
                    cancel(actionPerformed: {
                        dlg.visible = false
                    })
                }
            }
        }

        dlg.setVisible(true)
        dlg.dispose()

        if(okselected) {
            def val = list.getSelectedValue()
            if(val != null) {
                catalogField.text = val.catalog
                schemaField.text = val.schema
            }
        }
    }

    void showCatalogsAndSchemas() {

        test() {con ->
            def list = [] as List

            def schemas = con.getMetaData().getSchemas();
            def resmeta = schemas.getMetaData();
            def full = resmeta.getColumnCount() >= 2;
            while (schemas.next()) {
                def catalog = null
                def schema = schemas.getString(1);
                if (full) {
                    catalog = schemas.getString(2);
                }

                list << new CatalogSchemaValue(catalog, schema)
            }
            schemas.close();

            SwingUtilities.invokeLater {
                if(list.size() > 0) {
                    selectCatalogsAndSchemas(list)
                }
                else {
                    new PaneBuilder().information(resourceBundle.getString('connection.catalogs'), message: resourceBundle.getString('connection.nocatalogs'), owner: dialog)
                }
            }
        }
    }

    void test(Closure action) {

        PaneBuilder.runWithMonitor(dialog, resourceBundle.getString('connection.testing'), resourceBundle.getString('connection.testconnection'), resourceBundle.getString('connection.testfailed')) {

            Connection con
            try {
                Class.forName(driverField.text.trim())

                Properties conprops = new Properties()
                conprops.put("user", userField.text.trim())
                conprops.put("password", passwordField.text.trim())

                if(model.rows != null) {
                    model.rows.each() {row ->
                        conprops.put(row[0], row[1])
                    }
                }

                con = DriverManager.getConnection(urlField.text.trim(), conprops)

                if(action != null) {
                    action(con)
                }
                else {
                    SwingUtilities.invokeLater {
                        new PaneBuilder().information(resourceBundle.getString('connection.testconnection'), message: resourceBundle.getString('connection.testsuccessful'), owner: dialog)
                    }
                }
            }
            finally {
                 if(con != null) {
                     try {
                         con.close()
                     }
                     catch(Exception exc) {
                         Logger.getLogger(getClass().name).log(Level.SEVERE, 'Unable to close connection!', exc)
                     }
                 }
            }
        }
    }

    // ------------------------------------------------------------------------------

    ConnectionValue getConnectionValue() {

        def val = new ConnectionValue()

        if(id != null || id > 0) {
            val.id = id
        }
        else {
            val.id = System.currentTimeMillis()
        }

        val.description = descriptionField.text.trim()
        val.driver = driverField.text.trim()
        val.url = urlField.text.trim()
        val.user = userField.text.trim()
        val.password = passwordField.text.trim()
        val.catalog = catalogField.text.trim()
        val.schema = schemaField.text.trim()

        val.properties = [] as LinkedList

        if(model.rows != null) {
            model.rows.each() {row ->
                val.properties << new PropertyValue(row[0], row[1])
            }
        }

        val
    }

    void setConnectionValue(ConnectionValue val) {

        if(val == null) {
            val = new ConnectionValue()
        }
        else {
            dialog.title = resourceBundle.getString('connection.title.edit')
        }

        id = val.id
        descriptionField.text = val.description ?: ''
        driverField.text = val.driver ?: ''
        urlField.text = val.url ?: ''
        userField.text = val.user ?: ''
        passwordField.text = val.password ?: ''
        catalogField.text = val.catalog ?: ''
        schemaField.text = val.schema ?: ''

        def l = [] as ArrayList

        if(val.properties != null) {
            val.properties.each() {p ->
                l << [p.key, p.value]
            }
        }

        model.rows = l
    }
}